package tools;

import java.util.Vector;


public class MMME {
	
	private String id;
	private MMMEState currentState;
	private int numberOfProcess;
	
	private Vector<Fragment> provider;
	private Vector<Fragment> consumer;
	
	private Vector<Fragment> reservationList=new Vector<Fragment>();
	
	
	private boolean terminal;
	
	private int criticality;
	
	public MMME (String _id){
		if(_id.equals("Application"))
			terminal=true;
		else
			terminal=false;
		if(terminal){
			currentState = MMMEState.LinkedAtLeastOneConsumer;
		}
		else{
				currentState =  MMMEState.NotLinked;
		}
		id=_id;
		numberOfProcess=0;
		provider=new Vector<Fragment>();
		consumer=new Vector<Fragment>();
		setCriticality(0);
	}

	public String getID() {
		return id;
	}

	public synchronized MMMEState getState() {
		return currentState;
	}
	
	public synchronized void setNumberOfProcess(int numberOfProcess) {
		this.numberOfProcess = numberOfProcess;
	}

	public int getNumberOfProcess() {
		return numberOfProcess;
	}
	
	public synchronized Vector<Fragment> getChallengers() {
		Vector<Fragment> challengers=new Vector<Fragment>();
		for(int i=0; i<this.provider.size();i++)
			if(provider.get(i).getCurrentState()==FragmentState.Challenger)
				challengers.add(provider.get(i));
		return challengers;
	}
	
	private synchronized Vector<Fragment> getProviderIncluded() {
		Vector<Fragment> included=new Vector<Fragment>();
		for(int i=0; i<this.provider.size();i++)
			if(provider.get(i).getCurrentState()==FragmentState.Included)
				included.add(provider.get(i));
		return included;
	}
	private synchronized Vector<Fragment> getProviderSatisfied() {
		Vector<Fragment> satisfied=new Vector<Fragment>();
		for(int i=0; i<this.provider.size();i++)
			if(provider.get(i).getCurrentState()==FragmentState.Satisfied)
				satisfied.add(provider.get(i));
		return satisfied;
	}
	
	public Vector<Fragment> getConcurrents() {
		Vector<Fragment> concurrents=new Vector<Fragment>();
		for(int i=0; i<this.consumer.size();i++)
			if(consumer.get(i).getCurrentState()==FragmentState.Concurrency)
				concurrents.add(consumer.get(i));
		return concurrents;
	}
	
	public Vector<Fragment> getConsumerIncluded() {
		Vector<Fragment> included=new Vector<Fragment>();
		for(int i=0; i<this.consumer.size();i++)
			if(consumer.get(i).getCurrentState()==FragmentState.Included)
				included.add(consumer.get(i));
		return included;
	}
	
	
	public synchronized void addProvider(Fragment _provider){
		if(!provider.contains(_provider)){
			provider.add(_provider);
			Debug.println(_provider.getId() +"ADD as a provider");
		}
		else
			Debug.println(_provider.getId() +"already add as a provider to "+id);
	}

	
	public synchronized void addConsumer(Fragment _consumer){
		if(!consumer.contains(_consumer)){
			this.consumer.add(_consumer);
			Debug.println(_consumer.getId() +"ADD as a consumer to "+id);
		}
		else
			Debug.println(_consumer.getId() +"already add as a consumer");
	}
	
	public boolean isTerminal() {
		return terminal;
	}

	
	private int processNumberFromConsumerIncluded() {
		for(int i=0; i<consumer.size();i++){
			if(consumer.get(i).getCurrentState()==FragmentState.Included){
				return consumer.get(i).getProcessNumber();
			}
		}
		System.out.println("je suis iciiiiiiiiiiiiiiiiiiiiiiiii");
		return 0;
	}

	

	private boolean isOneProvider(){
		return (provider.size()>0);
	}
	
	private boolean isOneConsumer(){
		return(consumer.size()>0);
	}
	
	private boolean isOneSatisfiedProvider(){
		return (getProviderSatisfied().size()==1);
	}
	
	private boolean isOneMoreSatisfiedProvider(){
		if (getProviderSatisfied().size()>1)
			return true;
		else 
			if(isAllProviderIncludedInDifferentProcess()){
				return false;
			}
			else
				if(getProviderIncluded().size()+getProviderSatisfied().size()>1)
					return true;
		return false;
	}
	
	private boolean isAllProviderIncludedInDifferentProcess() {
		Vector<Integer> p = new Vector<Integer>();
		for(Fragment f:getProviderIncluded())
			if(!p.contains(f.getProcessNumber()))
				p.add(f.getProcessNumber());
		if(p.size()==getProviderIncluded().size())
			return true;
		return false;
	}

	private boolean isOneConsumerIncluded(){
		return (getConsumerIncluded().size()==1);
	}
	
	private boolean isConsumerIncludedInDifferentProcess(){
		if(isTerminal()){
			return true;
		}
		else{
		Vector<Integer> cpt=new Vector<Integer>();
		for(Fragment f: getConsumerIncluded()){
			if (!cpt.contains(f.getProcessNumber()))
				cpt.add(f.getProcessNumber());
		}
		return (cpt.size()==getConsumerIncluded().size());
		}
	}

	public synchronized void setCriticality(int criticality) {
		this.criticality += criticality;
	}

	public int getCriticality() {
		return criticality;
	}
	
	public synchronized void addReservator(Fragment res){
		if(!reservationList.contains(res)){
			reservationList.add(res);
			
//			synchronized(provider){
//				for(Fragment f : provider)
//					CompositionView.addLink(f, res);
//			}
			
			/**/
			Debug.println("MMME "+id+" : new reservator " + res.getId());
		}
	}
	
	public synchronized void removeReservator(Fragment res){
		if(reservationList.contains(res)){
			reservationList.remove(res);
			
//			synchronized(provider){
//				for(Fragment f : provider)
//					CompositionView.removeLink(f, res);
//			}
			/**/
			Debug.println("MMME "+id+" : end reservator " + res.getId());
		}
	}
	
	public synchronized Vector<Fragment> getReservationList(){
		return reservationList;
	}
	
	public Vector<Fragment> getProvider(){
		return provider;
	}
	
	public Vector<Fragment> getConsumer(){
		return consumer;
	}
	
	public String toString(){
		return id;
		
	}
	
	
	private synchronized int evalCriticality() {
//		Vector<Fragment> challengers=new Vector<Fragment>();
//		challengers.addAll(getConsumer());
//		if(challengers.size()>0){
//			Fragment criticality=challengers.get(0);
//			for(int i=0; i<challengers.size();i++){
//				if(criticality.getCriticity()<challengers.get(i).getCriticity()&& (challengers.get(i).getProcessNumber()!=0)){
//					criticality=challengers.get(i);
//				}
//			}
//			return criticality.getProcessNumber();
//		}
//		else{
//			System.out.println("error MMME: eval criticality Challengers");
//			return -1;
//		}
		return 1;
	}
	
	public synchronized void changeMMMEState(){
		boolean changeState=true;
		MMMEState previousState=currentState;
		//concurrent state
		if(currentState==MMMEState.Concurrent && changeState){
			numberOfProcess=evalCriticality();
			currentState=MMMEState.Incorporated;
			changeState=false;
		}
		
		// redundant state
		if(currentState==MMMEState.Redundant && changeState){
			if (isAllProviderIncludedInDifferentProcess()){
				currentState=MMMEState.Incorporated;
				numberOfProcess=1;
			}
			changeState=false;
		}
		
		// incorporated state
		if(currentState==MMMEState.Incorporated && changeState){
			if(isOneMoreSatisfiedProvider()){
				currentState=MMMEState.Redundant;
			}
			else {
				if(!isConsumerIncludedInDifferentProcess()){
					currentState=MMMEState.Concurrent;
				}
			}
			changeState=false;
		}
		
		// producible state
		if(currentState==MMMEState.Producible && changeState){
			if(isTerminal()){
				Debug.println(getID()+ " terminal !");
				currentState=MMMEState.Incorporated;
				if(numberOfProcess==0) numberOfProcess=1;
			}
			else{
				if(isOneMoreSatisfiedProvider()){
					currentState=MMMEState.Redundant;
				}	
				else{
					if(isOneConsumerIncluded()){
						currentState=MMMEState.Incorporated;
						numberOfProcess=processNumberFromConsumerIncluded();
					}
				}	
			}
			changeState=false;
		}
		
		// linked state
		if(currentState==MMMEState.Linked && changeState){
			changeState=false;
			if(isOneSatisfiedProvider()){
				if(isTerminal()){
					currentState=MMMEState.Incorporated;
					numberOfProcess=1;
				}
				else{
					currentState=MMMEState.Producible;
				}
			}
		}
		
		// LinkedAtLeastOneConsumer state
		if(currentState==MMMEState.LinkedAtLeastOneConsumer && changeState){
			if(isOneProvider()){
				currentState=MMMEState.Linked;
			}
			changeState=false;
		}
		
		// LinkedAtLeastOneProvider state
		if(currentState==MMMEState.LinkedAtLeastOneProvider && changeState){
			if(isOneConsumer()){
				currentState=MMMEState.LinkedAtLeastOneConsumer;
			}
			changeState=false;
		}
		
		// LinkedAtLeastOneProvider state
		if(currentState==MMMEState.NotLinked && changeState){
			if(isOneConsumer()){
				currentState=MMMEState.LinkedAtLeastOneConsumer;
			}
			else
				if(isOneProvider()){
					currentState=MMMEState.LinkedAtLeastOneProvider;
				}
			changeState=false;
		}
		if(currentState!=previousState)
			Debug.println(getID()+" mmme change to state : " +getState());
	}

	
	public int processFragmentRedundant(Fragment f){
		for(Fragment g:getProvider()){
			if(g.getCriticity()>f.getCriticity()){
				return 2;
			}
		}
		return 1;
	}

	public int checkProcessNumber(int number) {
		if(number!=numberOfProcess)
			numberOfProcess=number;
		return numberOfProcess;
	}

	public synchronized void majFragment(Fragment f){
		for(int i=0;i<consumer.size();i++){
			if(f.getId().equals(consumer.get(i).getId()))
				consumer.set(i, f);
		}
		for(int i=0;i<provider.size();i++){
			if(f.getId().equals(provider.get(i).getId()))
				provider.set(i, f);
		}
			
	}
	
}
